"""
PDF文档处理模块

这个模块负责：
1. 读取和解析PDF文件
2. 提取文本内容
3. 清洗和格式化文本
4. 将文本分割成合适的块

作者：xiaodeme@163.com
"""

import os
import re
import logging
from typing import List, Optional, Dict, Any
import pdfplumber
from .config import config

# 配置日志
logging.basicConfig(level=getattr(logging, config.LOG_LEVEL))
logger = logging.getLogger(__name__)

class PDFProcessor:
    """
    PDF处理器类
    
    主要功能：
    - 读取PDF文件
    - 提取文本内容
    - 处理中文编码问题
    """
    
    def __init__(self, pdf_path: str = None):
        """
        初始化PDF处理器
        
        Args:
            pdf_path (str, optional): PDF文件路径，默认使用配置中的路径
        """
        self.pdf_path = pdf_path or config.PDF_PATH
        logger.info(f"初始化PDF处理器，文件路径: {self.pdf_path}")
        
        # 验证文件是否存在
        if not os.path.exists(self.pdf_path):
            raise FileNotFoundError(f"PDF文件不存在: {self.pdf_path}")
    
    def extract_text(self) -> str:
        """
        从PDF文件中提取所有文本
        
        Returns:
            str: 提取的文本内容
            
        Raises:
            Exception: 当PDF读取失败时抛出异常
        """
        logger.info("开始提取PDF文本内容...")
        
        try:
            all_text = ""
            page_count = 0
            
            # 使用pdfplumber读取PDF
            with pdfplumber.open(self.pdf_path) as pdf:
                logger.info(f"PDF文件包含 {len(pdf.pages)} 页")
                
                for page_num, page in enumerate(pdf.pages, 1):
                    # 提取页面文本
                    page_text = page.extract_text()
                    
                    if page_text:
                        all_text += f"\n=== 第{page_num}页 ===\n"
                        all_text += page_text
                        all_text += "\n"
                        page_count += 1
                        
                        # 每处理10页打印一次进度
                        if page_num % 10 == 0:
                            logger.info(f"已处理 {page_num} 页...")
                    else:
                        logger.warning(f"第{page_num}页没有提取到文本内容")
            
            logger.info(f"PDF文本提取完成，共处理了 {page_count} 页，文本长度: {len(all_text)} 字符")
            return all_text
            
        except Exception as e:
            logger.error(f"PDF文本提取失败: {str(e)}")
            raise Exception(f"无法读取PDF文件: {str(e)}")
    
    def get_pdf_info(self) -> Dict[str, Any]:
        """
        获取PDF文件的基本信息
        
        Returns:
            Dict[str, Any]: PDF文件信息字典
        """
        logger.info("获取PDF文件信息...")
        
        try:
            with pdfplumber.open(self.pdf_path) as pdf:
                metadata = pdf.metadata or {}
                
                info = {
                    'file_path': self.pdf_path,
                    'file_size': os.path.getsize(self.pdf_path),
                    'page_count': len(pdf.pages),
                    'title': metadata.get('Title', '未知'),
                    'author': metadata.get('Author', '未知'),
                    'creator': metadata.get('Creator', '未知'),
                    'creation_date': metadata.get('CreationDate', '未知'),
                    'modification_date': metadata.get('ModDate', '未知')
                }
                
                logger.info(f"PDF信息获取成功: {info['page_count']} 页, 大小: {info['file_size']} 字节")
                return info
                
        except Exception as e:
            logger.error(f"获取PDF信息失败: {str(e)}")
            return {'error': str(e)}

class TextCleaner:
    """
    文本清洗类
    
    负责：
    - 清理无效字符
    - 格式化文本
    - 处理中文特殊字符
    """
    
    def __init__(self):
        """初始化文本清洗器"""
        logger.info("初始化文本清洗器")
    
    def clean_text(self, text: str) -> str:
        """
        清洗文本内容
        
        Args:
            text (str): 原始文本
            
        Returns:
            str: 清洗后的文本
        """
        if not text:
            return ""
        
        logger.debug("开始清洗文本...")
        
        # 1. 移除多余的空白字符
        text = re.sub(r'\s+', ' ', text)
        
        # 2. 移除页面分隔符标记（我们之前添加的）
        text = re.sub(r'=== 第\d+页 ===', '', text)
        
        # 3. 移除特殊字符但保留中文标点
        # 保留：中文字符、英文字母、数字、常用标点符号
        text = re.sub(r'[^\u4e00-\u9fff\w\s\.\,\!\?\;\:\(\)\[\]\-\=\+\*\/\%\@\#\&\<\>\|\~\`\'\"\《\》\，\。\！\？\；\：\（\）\【\】\、\—\…\·]', '', text)
        
        # 4. 处理连续的标点符号
        text = re.sub(r'[\.]{2,}', '...', text)
        text = re.sub(r'[，]{2,}', '，', text)
        
        # 5. 移除行首和行尾的空白
        text = text.strip()
        
        # 6. 处理段落分隔，确保段落之间有适当的分隔
        text = re.sub(r'\n\s*\n', '\n\n', text)
        
        logger.debug(f"文本清洗完成，处理后长度: {len(text)} 字符")
        return text

class TextSplitter:
    """
    文本分割类
    
    负责将长文本分割成适合处理的小块
    """
    
    def __init__(self, chunk_size: int = None, chunk_overlap: int = None):
        """
        初始化文本分割器
        
        Args:
            chunk_size (int, optional): 每个文本块的大小，默认使用配置值
            chunk_overlap (int, optional): 文本块之间的重叠大小，默认使用配置值
        """
        self.chunk_size = chunk_size or config.CHUNK_SIZE
        self.chunk_overlap = chunk_overlap or config.CHUNK_OVERLAP
        
        logger.info(f"初始化文本分割器，块大小: {self.chunk_size}, 重叠: {self.chunk_overlap}")
        
        # 验证参数
        if self.chunk_overlap >= self.chunk_size:
            raise ValueError("重叠大小不能大于等于块大小")
    
    def split_text(self, text: str) -> List[str]:
        """
        将文本分割成多个块
        
        Args:
            text (str): 待分割的文本
            
        Returns:
            List[str]: 分割后的文本块列表
        """
        if not text:
            return []
        
        logger.info(f"开始分割文本，原文本长度: {len(text)} 字符")
        
        # 如果文本长度小于等于chunk_size，直接返回单个块
        if len(text) <= self.chunk_size:
            logger.info(f"文本长度({len(text)})小于等于块大小({self.chunk_size})，直接返回单个块")
            return [text.strip()]
        
        chunks = []
        start = 0
        
        while start < len(text):
            # 计算当前块的结束位置
            end = start + self.chunk_size
            
            # 如果不是最后一块，尝试在合适的位置分割（如句号、换行符等）
            if end < len(text):
                # 在合适的分割点分割
                end = self._find_split_point(text, start, end)
            else:
                end = len(text)
            
            # 提取文本块
            chunk = text[start:end].strip()
            if chunk:  # 只添加非空的文本块
                chunks.append(chunk)
            
            # 计算下一个块的开始位置（考虑重叠）
            next_start = end - self.chunk_overlap
            
            # 防止无限循环：如果下一个起始位置没有前进，就结束
            if next_start <= start:
                logger.debug(f"检测到可能的无限循环，结束分割。start={start}, next_start={next_start}")
                break
                
            start = next_start
        
        logger.info(f"文本分割完成，共生成 {len(chunks)} 个文本块")
        return chunks
    
    def _find_split_point(self, text: str, start: int, end: int) -> int:
        """
        寻找合适的文本分割点
        
        Args:
            text (str): 原文本
            start (int): 起始位置
            end (int): 期望的结束位置
            
        Returns:
            int: 实际的分割位置
        """
        # 优先级：句号 > 问号感叹号 > 分号冒号 > 逗号 > 换行符 > 空格
        split_chars = ['。', '！', '？', '；', '：', '，', '\n', ' ']
        
        # 在一定范围内寻找分割点
        search_range = min(100, self.chunk_size // 4)  # 搜索范围不超过块大小的1/4
        
        for i in range(end - 1, max(start, end - search_range), -1):
            if text[i] in split_chars:
                return i + 1
        
        # 如果找不到合适的分割点，就在原位置分割
        return end

# 测试函数
def test_pdf_processor():
    """
    测试PDF处理功能
    """
    print("=== 测试PDF处理器 ===")
    
    try:
        # 创建PDF处理器
        processor = PDFProcessor()
        
        # 获取PDF信息
        pdf_info = processor.get_pdf_info()
        print(f"PDF信息: {pdf_info}")
        
        # 提取文本（只提取前1000字符进行测试）
        full_text = processor.extract_text()
        print(f"提取的文本长度: {len(full_text)} 字符")
        print(f"文本预览: {full_text[:500]}...")
        
        # 测试文本清洗
        cleaner = TextCleaner()
        cleaned_text = cleaner.clean_text(full_text[:1000])
        print(f"清洗后文本长度: {len(cleaned_text)} 字符")
        print(f"清洗后文本预览: {cleaned_text[:300]}...")
        
        # 测试文本分割
        splitter = TextSplitter()
        chunks = splitter.split_text(cleaned_text)
        print(f"分割后块数: {len(chunks)}")
        if chunks:
            print(f"第一块文本: {chunks[0]}")
        
        print("✅ PDF处理器测试完成")
        
    except Exception as e:
        print(f"❌ PDF处理器测试失败: {e}")

if __name__ == "__main__":
    test_pdf_processor() 